#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <queue>
#include <pthread.h>
#include "thread.hpp"
#include "task.hpp"
#include "lock.hpp"

using namespace std;

#define N 5

template<class T>
class ThreadPool{
private:
    ThreadPool(int num = N): _num(num) {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool<T> &tp) = delete;
    ThreadPool &operator=(const ThreadPool<T> &tp) = delete;

public:

    static ThreadPool<T>* getInstance(){
        if(_instance == nullptr){
            LockGuard lockguard(&_inst_lock);
            if (_instance == nullptr){
                _instance = new ThreadPool<T>();
                _instance->init();
                _instance->start();
                cout << "线程池单例形成" << endl;
            }
        }

        return _instance;
    }

    ~ThreadPool(){
        //线程结束前进行阻塞式等待，保证所有线程都结束后才销毁锁
        for(auto& t : _threads){
            t.join();
        }
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

    void lockQueue(){
        pthread_mutex_lock(&_lock);
    }

    void unlockQueue(){
        pthread_mutex_unlock(&_lock);
    }

    void threadWait(){
        pthread_cond_wait(&_cond, &_lock);
    }

    void threadWakeUp(){
        pthread_cond_signal(&_cond);
    }

    bool empty(){
        return _tasks.empty();
    }

    pthread_mutex_t* getlock(){
        return &_lock;
    }


    //回调函数
    //类内的成员函数包含this指针，不满足void *outine(void* args)，加static可以消除this
    static void threadRoutine(void* args){
        // //规定当线程退出时自动释放线程资源，被分离的线程不能被join
        // pthread_detach(pthread_self());
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);

        while(1){
            T t;
            {
                LockGuard lockguard(tp->getlock());
                // 任务为空就等待
                while(tp->empty()){
                    tp->threadWait();
                }
                //从共享区拿到私有区
                t = tp->popTask();
                // //处理任务不应该在临界区处理
                // t.run(); // err
            }

            t();
            
            
        }
    }

    //创建一批线程对象，放在线程池中
    void init(){
        for (int i = 0; i < _num;i++){
            //向vector中插入线程号为i，执行threadRountine、参数为this的线程
            _threads.push_back(Thread(i, threadRoutine, this));
            cout << i << " thread running" << endl;
        }
    }

    //启动线程池中的线程(根据线程对象创建对应线程，并运行)
    void start(){
        for(auto& t : _threads){
            t.run();
        }
    }

    void check(){
        for(auto& t : _threads){
            cout << t.threadname() << " running... " << endl;
        }
    }

    void pushTask(const T& t){
        LockGuard lockguard(&_lock);
        _tasks.push(t);
        //添加一个任务之后唤醒一个等待中的线程
        threadWakeUp();
    }

    //在加锁环境中使用，不需要再次加锁
    T popTask(){
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

private:
    vector<Thread> _threads;    //线程池
    int _num;

    queue<T> _tasks;            //任务队列
    pthread_mutex_t _lock;
    pthread_cond_t _cond;        //条件变量，线程等待的地方

    //单例
    static ThreadPool<T> *_instance;
    static pthread_mutex_t _inst_lock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::_inst_lock = PTHREAD_MUTEX_INITIALIZER;